﻿using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using OpenPasteSpider.projectmodel;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ObjectMapping;


namespace OpenPasteSpider
{
    /// <summary>
    /// 对象缓存
    /// </summary>
    public class PublicModelHelper : ISingletonDependency
    {

        /// <summary>
        /// 
        /// </summary>
        private IServiceProvider _serviceProvider;
        /// <summary>
        /// 
        /// </summary>
        private ICacheHelper _cache;

        /// <summary>
        /// 
        /// </summary>
        private readonly IObjectMapper _objectMapper;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <param name="cache"></param>
        /// <param name="objectMapper"></param>
        public PublicModelHelper(
            IServiceProvider serviceProvider,
            ICacheHelper cache,
            IObjectMapper objectMapper
            )
        {
            _serviceProvider = serviceProvider;
            _cache = cache;
            _objectMapper = objectMapper;
        }



        #region 按照ID获取对象，对象缓存

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="_dbContext"></param>
        /// <returns></returns>
        public async Task<AppInfoDto> ItemAppInfo(int id, IOpenPasteSpiderDbContext _dbContext)
        {
            var appinfo = await _cache.GetObjectAsync<AppInfoDto>(string.Format(PublicString.CacheItemAppInfo, id));
            if (appinfo == null || appinfo == default)
            {
                //using var scope = _serviceProvider.CreateScope();
                //using var _dbContext = scope.ServiceProvider.GetRequiredService<IOpenPasteSpiderDbContext>();
                var info = await _dbContext.AppInfo.Where(x => x.Id == id).AsNoTracking().FirstOrDefaultAsync();
                if (info != null && info != default)
                {
                    await _cache.SetObjectAsync<AppInfo>(string.Format(PublicString.CacheItemAppInfo, id), info);
                    return _objectMapper.Map<AppInfo, AppInfoDto>(info);
                }
            }
            return appinfo;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> ItemAppClean(int id)
        {
            if (id != 0)
            {
                return await _cache.DeleteAsync(string.Format(PublicString.CacheItemAppInfo, id));
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="_dbContext"></param>
        /// <returns></returns>
        public async Task<ModelInfoDto> ItemModelInfoAsync(int id, IOpenPasteSpiderDbContext _dbContext)
        {
            var appinfo = await _cache.GetObjectAsync<ModelInfoDto>(string.Format(PublicString.CacheItemModelInfo, id));
            if (appinfo == null || appinfo == default)
            {
                //using var scope = _serviceProvider.CreateScope();
                //using var _dbContext = scope.ServiceProvider.GetRequiredService<IOpenPasteSpiderDbContext>();
                var info = await _dbContext.ModelInfo.Where(x => x.Id == id).Include(x => x.Service).AsNoTracking().FirstOrDefaultAsync();
                if (info != null && info != default)
                {
                    await _cache.SetObjectAsync<ModelInfo>(string.Format(PublicString.CacheItemModelInfo, id), info);
                    return _objectMapper.Map<ModelInfo, ModelInfoDto>(info);
                }
            }
            return appinfo;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> ItemModelCleanAsync(int id)
        {
            return await _cache.DeleteAsync(string.Format(PublicString.CacheItemModelInfo, id));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="_dbContext"></param>
        /// <returns></returns>
        public async Task<ServiceInfoDto> ItemServiceInfo(int id, IOpenPasteSpiderDbContext _dbContext)
        {
            var appinfo = await _cache.GetObjectAsync<ServiceInfoDto>(string.Format(PublicString.CacheItemServiceInfo, id));
            if (appinfo == null || appinfo == default)
            {
                //using var scope = _serviceProvider.CreateScope();
                //using var _dbContext = scope.ServiceProvider.GetRequiredService<IOpenPasteSpiderDbContext>();
                var info = await _dbContext.ServiceInfo.Where(x => x.Id == id).Include(x => x.Project).AsNoTracking().FirstOrDefaultAsync();
                if (info != null && info != default)
                {
                    await _cache.SetObjectAsync<ServiceInfo>(string.Format(PublicString.CacheItemServiceInfo, id), info);
                    return _objectMapper.Map<ServiceInfo, ServiceInfoDto>(info);
                }
            }
            return appinfo;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> ItemServiceClean(int id)
        {
            return await _cache.DeleteAsync(string.Format(PublicString.CacheItemServiceInfo, id));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="_dbContext"></param>
        /// <returns></returns>
        public async Task<ProjectInfoDto> ItemProjectInfo(int id, IOpenPasteSpiderDbContext _dbContext)
        {
            var appinfo = await _cache.GetObjectAsync<ProjectInfoDto>(string.Format(PublicString.CacheItemProjectInfo, id));
            if (appinfo == null || appinfo == default)
            {
                //using var scope = _serviceProvider.CreateScope();
                //using var _dbContext = scope.ServiceProvider.GetRequiredService<IOpenPasteSpiderDbContext>();
                var info = await _dbContext.ProjectInfo.Where(x => x.Id == id).AsNoTracking().FirstOrDefaultAsync();
                if (info != null && info != default)
                {
                    await _cache.SetObjectAsync<ProjectInfoDto>(string.Format(PublicString.CacheItemProjectInfo, id), appinfo);
                    return _objectMapper.Map<ProjectInfo, ProjectInfoDto>(info);
                }
            }
            return appinfo;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> ItemProjectClean(int id)
        {
            return await _cache.DeleteAsync(string.Format(PublicString.CacheItemProjectInfo, id));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="_dbContext"></param>
        /// <returns></returns>
        public async Task<LinuxInfoDto> ItemLinuxInfo(int id, IOpenPasteSpiderDbContext _dbContext)
        {
            var appinfo = await _cache.GetObjectAsync<LinuxInfoDto>(string.Format(PublicString.CacheItemLinuxInfo, id));
            if (appinfo == null || appinfo == default)
            {
                //using var scope = _serviceProvider.CreateScope();
                //using var _dbContext = scope.ServiceProvider.GetRequiredService<IOpenPasteSpiderDbContext>();
                var info = await _dbContext.LinuxInfo.Where(x => x.Id == id).AsNoTracking().FirstOrDefaultAsync();
                if (info != null && info != default)
                {
                    await _cache.SetObjectAsync<LinuxInfo>(string.Format(PublicString.CacheItemLinuxInfo, id), info);
                    return _objectMapper.Map<LinuxInfo, LinuxInfoDto>(info);
                }
            }
            return appinfo;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> ItemLinuxClean(int id)
        {
            return await _cache.DeleteAsync(string.Format(PublicString.CacheItemLinuxInfo, id));
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> ItemStoreClean(int id)
        {
            return await _cache.DeleteAsync(string.Format(PublicString.CacheItemStoreInfo, id));
        }

        /// <summary>
        /// 根据服务ID和环境，获取环境信息
        /// </summary>
        /// <param name="id">ServiceInfo.Id</param>
        /// <param name="_code">ModelCode</param>
        /// <param name="_dbContext">ModelCode</param>
        /// <returns></returns>
        public async Task<ModelInfoDto> ReadModelInfoByServiceIdAsync(int id, string _code, IOpenPasteSpiderDbContext _dbContext)
        {


            //var appinfo = await _cache.GetObjectAsync<ModelInfoDto>(string.Format(PublicString.CacheItemModelInfo, id));
            //if (appinfo == null || appinfo == default)
            //{
            //using var scope = _serviceProvider.CreateScope();
            //using var _dbContext = scope.ServiceProvider.GetRequiredService<IOpenPasteSpiderDbContext>();
            var info = await _dbContext.ModelInfo.Where(x => x.Service.Id == id && x.Code == _code).Include(x => x.Service).AsNoTracking().FirstOrDefaultAsync();
            if (info != null && info != default)
            {
                //await _cache.SetObjectAsync<ModelInfo>(string.Format(PublicString.CacheItemModelInfo, id), info);
                return _objectMapper.Map<ModelInfo, ModelInfoDto>(info);
            }
            //}
            return null;
        }


        #endregion


        /// <summary>
        /// 模型与实际内容的替换
        /// </summary>
        /// <param name="command"></param>
        /// <param name="_linux"></param>
        /// <param name="_project"></param>
        /// <param name="_service"></param>
        /// <param name="_model"></param>
        /// <param name="_app"></param>
        public string BuildCommandString(
            string command,
            LinuxInfoDto _linux = null,
            ProjectInfoDto _project = null,
            ServiceInfoDto _service = null,
            ModelInfoDto _model = null,
            AppInfoDto _app = null)
        {
            if (command.Contains("{{App."))
            {
                //var _app = ItemAppInfo(appid).Result;
                if (_app != null && _app != default)
                {
                    command = command
                        .Replace("{{App.Address}}", _app.Address)
                        .Replace("{{App.AppID}}", _app.AppID)
                        .Replace("{{App.Name}}", _app.Name)
                        .Replace("{{App.Id}}", _app.Id.ToString());
                    if (!String.IsNullOrEmpty(_app.OutPort))
                    {
                        var ports = _app.OutPort.Split(',');
                        for (var k = 0; k < ports.Length; k++)
                        {
                            command = command.Replace("{{App.Port[" + k + "]}}", ports[k]);
                        }
                    }
                }
            }

            if (command.Contains("{{Service."))
            {
                //var _service = ItemServiceInfo(serviceid).Result;
                if (_service != null && _service != default)
                {
                    command = command
                        .Replace("{{Service.Code}}", _service.Code)
                        .Replace("{{Service.Args}}", _service.OtherArgs)
                        .Replace("{{Service.Id}}", _service.Id.ToString())
                        .Replace("{{Service.DirectPath}}", _service.DirectPath.ToString())
                        .Replace("{{Service.NeedMapping}}", _service.NeedMapping.ToString())
                        .Replace("{{Service.FileModel}}", _service.FileModel.ToString())
                        .Replace("{{Service.OtherArgs}}", _service.OtherArgs.ToString());
                    if (!String.IsNullOrEmpty(_service.ListenPorts))
                    {
                        var ports = _service.ListenPorts.Split(',');
                        for (var k = 0; k < ports.Length; k++)
                        {
                            command = command.Replace("{{Service.Port[" + k + "]}}", ports[k]);
                        }
                    }
                }
            }

            if (command.Contains("{{Model."))
            {
                //var _model = ItemModelInfo(modelid).Result;
                if (_model != null && _model != default)
                {
                    command = command
                        .Replace("{{Model.Code}}", _model.Code)
                        .Replace("{{Model.Id}}", _model.Id.ToString());
                }
            }

            if (command.Contains("{{Linux."))
            {
                //var _linux = ItemLinuxInfo(linuxid).Result;
                if (_linux != null && _linux != default)
                {
                    command = command
                        .Replace("{{Linux.RemoteIP}}", _linux.RemoteIP)
                        .Replace("{{Linux.Id}}", _linux.Id.ToString())
                        .Replace("{{Linux.OpenPorts}}", _linux.OpenPorts.ToString())
                        .Replace("{{Linux.BuildHost}}", _linux.BuildHost.ToString())
                        .Replace("{{Linux.WorkDir}}", _linux.WorkDir.ToString())
                        .Replace("{{Linux.NginxDir}}", _linux.NginxDir.ToString())
                        .Replace("{{Linux.Unix}}", _linux.Unix.ToString())
                        .Replace("{{Linux.Tool}}", _linux.Tool.ToString());
                }
            }
            return command;
        }

        /// <summary>
        /// 任务排重 project:service:code
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public void PlanRunCheck(PlanInfo info)
        {
            var _esists = _cache.Exists(string.Format(PublicString.CacheLockSpiderRun, info.ProjectId, info.ServiceId, info.ModelId, info.OrderModel.ToString(), info.AppId));
            if (_esists)
            {
                throw new PasteException("任务重复了，请勿频繁的发起同一个任务！");
            }
        }

        /// <summary>
        /// 记录任务运行准备运行
        /// </summary>
        /// <param name="info"></param>
        /// <param name="minute"></param>
        public void PlanRunTag(PlanInfo info, int minute = 10)
        {

            _cache.Set(string.Format(PublicString.CacheLockSpiderRun, info.ProjectId, info.ServiceId, info.ModelId, info.OrderModel.ToString(), info.AppId), DateTime.Now.ToString(), TimeSpan.FromMinutes(minute));

        }

        /// <summary>
        /// 释放任务标记
        /// </summary>
        /// <param name="info"></param>
        public void PlanRunComplete(PlanInfo info)
        {

            _cache.Delete(string.Format(PublicString.CacheLockSpiderRun, info.ProjectId, info.ServiceId, info.ModelId, info.OrderModel.ToString(), info.AppId));

        }
    }
}
